/**
 * 地图底图工具
 */
export default class MapTileTool {
  constructor(viewer) {
    this.viewer = viewer;
  }

  /**
   * 加载geoserver发布的WMS底图
   * @param {*} url
   * @param {*} layers 底图的图层名称
   * @param {*} name 自定义图层名称
   * @returns
   */
  loadGeoserveTile(url, layers, name) {
    var Cesium = Cesium;
    let parameters = {
      service: 'WMS',
      format: 'image/jpeg',
      tiled: true, //是否是切片
      version: '1.1.1',
      SRS: 'EPSG:3857',
      exceptions: 'application/vnd.ogc.se_inimage',
      transparent: 'true', //jpeg图片格式下无效
      request: 'GetMap',
    };
    let geoLayer = new Cesium.WebMapServiceImageryProvider({
      url: url,
      layers: layers, //佛山卫星
      // url:
      //   "http://services.arcgisonline.com/ArcGIS/rest/services/World_Imagery/MapServer",//web墨卡托的天地图卫星
      // url:
      //   "http://webrd02.is.autonavi.com/appmaptile?lang=zh_cn&size=1&scale=1&style=8&x={x}&y={y}&z={z}", //高德街道版底图

      wrapX: false, //是否可以重复平铺
      enablePickFeatures: false,
      tilingScheme: new Cesium.WebMercatorTilingScheme({
        numberOfLevelZeroTilesX: 1,
        numberOfLevelZeroTilesY: 1,
      }),
      parameters,
    });
    var baseImageLayer = new Cesium.ImageryLayer(geoLayer);
    baseImageLayer.name = name;
    this.viewer.imageryLayers.add(baseImageLayer);
    return baseImageLayer;
  }
  /**
   * 加载arcgis
   * @param {*} mapUrl
   * @param {*} name 自定义图层名称
   * @returns
   */
  loadArcgisTile(mapUrl, name) {
    let arcgis_layer = new Cesium.ArcGisMapServerImageryProvider({
      url: mapUrl,
    });
    var baseImageLayer = new Cesium.ImageryLayer(arcgis_layer);
    baseImageLayer.name = name;
    this.viewer.imageryLayers.add(baseImageLayer);
    return baseImageLayer;
  }
  /**
   * 加载高德
   * @param {*} mapUrl
   * @param {*} name 自定义图层名称
   * @returns
   */
  loadGaodeTile(mapUrl, name) {
    let gaode_layer = new Cesium.UrlTemplateImageryProvider({
      url: mapUrl,
    });
    var baseImageLayer = new Cesium.ImageryLayer(gaode_layer);
    baseImageLayer.name = name;
    this.viewer.imageryLayers.add(baseImageLayer);
    return baseImageLayer;
  }
  /**
   * 加载天地图
   * @param {*} mapUrl
   * @param {*} layer
   * @param {*} name 自定义图层名称
   * @returns
   */
  loadTDtuTile(mapUrl, layer, name) {
    let td_layer = new Cesium.WebMapTileServiceImageryProvider({
      url: mapUrl,
      layer: layer,
      style: 'default',
      format: 'tiles',
      tileMatrixSetID: 'w',
      maximumLevel: 18,
    });
    var baseImageLayer = new Cesium.ImageryLayer(td_layer);
    baseImageLayer.name = name;
    this.viewer.imageryLayers.add(baseImageLayer);
    return baseImageLayer;
  }

  /**
   * 加载本地离线瓦片，谷歌瓦片
   * @param {String} url
   * @param {*} name
   * @returns
   */
  loadLocalTile(url, name) {
    let local_layer = new Cesium.UrlTemplateImageryProvider({
      // 下面是我的瓦片地址部署在本地，可以根据自己实际修改
      url: url,
      fileExtension: 'png',
      errorEvent: () => {},
    });
    var baseImageLayer = new Cesium.ImageryLayer(local_layer);
    baseImageLayer.name = name;
    this.viewer.imageryLayers.add(baseImageLayer);
    return baseImageLayer;
  }

  /**
   * 移除3DTile
   * @param {Object} tileset
   */
  remove3DTile(tileset) {
    this.viewer.scene.primitives.remove(tileset);
  }

  /**
   * 加载3D tile
   *
   *  @param {*} tileUrl url
   *  @param {*} height 模型离地高度
   *  @param {*} tileLoadedFn 加载完成回调函数
   *  @param {*} tileLoadingFn 加载中回调函数
   *  @return {Promise} 一个Promise对象
   */
  load3DTile(tileUrl, height = 0, tileLoadedFn, tileLoadingFn) {
    var _this = this;
    return new Promise((resolve, reject) => {
      //创建倾斜摄影
      var tileset = new Cesium.Cesium3DTileset({
        //相对路径
        url: tileUrl,
        modelMatrix: Cesium.Matrix4.IDENTITY,
        
        // skipLevelOfDetail: true,
        // preferLeaves: true,
        // baseScreenSpaceError: 1024,
        // maximumScreenSpaceError: 256, // 数值加大，能让最终成像变模糊
        // skipScreenSpaceErrorFactor: 16,
        // skipLevels: 1,
        // immediatelyLoadDesiredLevelOfDetail: false,
        // loadSiblings: true, // 如果为true则不会在已加载完概况房屋后，自动从中心开始超清化房屋
        // cullWithChildrenBounds: true,
        // cullRequestsWhileMoving: true,
        // cullRequestsWhileMovingMultiplier: 10, // 值越小能够更快的剔除
        // preloadWhenHidden: true,
        // maximumMemoryUsage: 512, // 内存分配变小有利于倾斜摄影数据回收，提升性能体验
        // progressiveResolutionHeightFraction: 0.5, // 数值偏于0能够让初始加载变得模糊
        // dynamicScreenSpaceErrorDensity: 0.1, // 数值加大，能让周边加载变快
        // dynamicScreenSpaceErrorFactor: 1, // 不知道起了什么作用没，反正放着吧先
        // dynamicScreenSpaceError: false // 根据测试，有了这个后，会在真正的全屏加载完之后才清晰化房屋
      });
      //加载到球体上
      this.viewer.scene.primitives.add(tileset);
      //加载完数据后，进行相机视角设置
      tileset.readyPromise.then(function () {
        console.log('tileset 创建成功');
        
        // _this.changeHeight(tileset, height);
        var boundingSphere = tileset.boundingSphere;
        _this.viewer.zoomTo(
          tileset,
          new Cesium.HeadingPitchRange(0.0, -0.5, boundingSphere.radius * 2.0)
        );
        //监听3dtileset加载进度，可在进度获取中用于自定义业务或者动画操作
        tileset.loadProgress.addEventListener(function(numberOfPendingRequests,numberOfTilesProcessing) {
          if (numberOfPendingRequests === 0 && numberOfTilesProcessing === 0) {
            //表示所有加载完毕
            tileLoadedFn && tileLoadedFn();
            return;
          }
          tileLoadingFn && tileLoadingFn(numberOfPendingRequests, numberOfTilesProcessing);
        });
        resolve(tileset);
      });
    }).catch((e) => {
      console.log(e);
    });
  }

  /**
   * 加载建筑类型3DTile
   * @param {*} tileUrl tile url
   * @param {*} tileLoadedFn 加载完成回调函数
   * @param {*} tileLoadingFn 加载中回调函数
   * @returns
   */
  loadShp3DTile(tileUrl, tileLoadedFn, tileLoadingFn) {
    var _this = this;
    return new Promise((resolve, reject) => {
      //创建倾斜摄影
      var tileset = new Cesium.Cesium3DTileset({
        //相对路径
        url: tileUrl,
        modelMatrix: Cesium.Matrix4.IDENTITY,
        // skipLevelOfDetail: true,
        // preferLeaves: true,
        // baseScreenSpaceError: 1024,
        // maximumScreenSpaceError: 256, // 数值加大，能让最终成像变模糊
        // skipScreenSpaceErrorFactor: 16,
        // skipLevels: 1,
        // immediatelyLoadDesiredLevelOfDetail: false,
        // loadSiblings: true, // 如果为true则不会在已加载完概况房屋后，自动从中心开始超清化房屋
        // cullWithChildrenBounds: true,
        // cullRequestsWhileMoving: true,
        // cullRequestsWhileMovingMultiplier: 10, // 值越小能够更快的剔除
        // preloadWhenHidden: true,
        // maximumMemoryUsage: 512, // 内存分配变小有利于倾斜摄影数据回收，提升性能体验
        // progressiveResolutionHeightFraction: 0.5, // 数值偏于0能够让初始加载变得模糊
        // dynamicScreenSpaceErrorDensity: 0.1, // 数值加大，能让周边加载变快
        // dynamicScreenSpaceErrorFactor: 1, // 不知道起了什么作用没，反正放着吧先
        // dynamicScreenSpaceError: false // 根据测试，有了这个后，会在真正的全屏加载完之后才清晰化房屋
      });
      //加载到球体上
      this.viewer.scene.primitives.add(tileset);

      //加载完数据后，进行相机视角设置
      tileset.readyPromise.then(function () {
        console.log('tileset 创建成功');
        resolve(tileset);
        //修改白膜建筑的样式
        tileset.style = new Cesium.Cesium3DTileStyle({
          color: {
            // conditions: [
            //   ['${floor} >= 30', 'rgba(45, 0, 75, 0.5)'],
            //   ['${floor} >= 20', 'rgb(102, 71, 151)'],
            //   ['${floor} >= 15', 'rgb(170, 162, 204)'],
            //   ['${floor} >= 11', 'rgb(224, 226, 238)'],
            //   ['${floor} >= 9', 'rgb(252, 230, 200)'],
            //   ['${floor} >= 7', 'rgb(248, 176, 87)'],
            //   ['${floor} >= 5', "color('skyblue', 0.5)"],
            //   ['true', 'rgb(127, 59, 8)']
            // ]
            conditions: [['true', 'rgb(127, 59, 8)']],
          },
        });
        var boundingSphere = tileset.boundingSphere;
        _this.viewer.zoomTo(
          tileset,
          new Cesium.HeadingPitchRange(0.0, -0.5, boundingSphere.radius * 2.0)
        );
        //监听3dtileset加载进度，可在进度获取中用于自定义业务或者动画操作
        tileset.loadProgress.addEventListener(function (
          numberOfPendingRequests,
          numberOfTilesProcessing
        ) {
          if (numberOfPendingRequests === 0 && numberOfTilesProcessing === 0) {
            //表示所有加载完毕
            tileLoadedFn && tileLoadedFn();
            return;
          }
          tileLoadingFn &&
            tileLoadingFn(numberOfPendingRequests, numberOfTilesProcessing);
        });
        //修改着色器
        // tileset.tileVisible.addEventListener(function (tile) {
        //   var content = tile.content;
        //   var featuresLength = content.featuresLength;
        //   for (var i = 0; i < featuresLength; i += 2) {
        //     let feature = content.getFeature(i)
        //     let model = feature.content._model

        //     if (model && model._sourcePrograms && model._rendererResources) {
        //       Object.keys(model._sourcePrograms).forEach(key => {
        //         let program = model._sourcePrograms[key]
        //         let fragmentShader = model._rendererResources.sourceShaders[program.fragmentShader];
        //         let v_position = "";
        //         if (fragmentShader.indexOf(" v_positionEC;") != -1) {
        //           v_position = "v_positionEC";
        //         } else if (fragmentShader.indexOf(" v_pos;") != -1) {
        //           v_position = "v_pos";
        //         }
        //         const color = `vec4(${feature.color.toString()})`;

        //         model._rendererResources.sourceShaders[program.fragmentShader] =
        //           "varying vec3 " + v_position + ";\n" +
        //           "void main(void){\n" +
        //           "    vec4 position = czm_inverseModelView * vec4(" + v_position + ",1);\n" +
        //           "    float glowRange = 360.0;\n" +
        //           "    gl_FragColor = " + color + ";\n" +
        //           // "    gl_FragColor = vec4(0.2,  0.5, 1.0, 1.0);\n" +
        //           "    gl_FragColor *= vec4(vec3(position.z / 100.0), 1.0);\n" +
        //           "    float time = fract(czm_frameNumber / 360.0);\n" +
        //           "    time = abs(time - 0.5) * 2.0;\n" +
        //           "    float diff = step(0.005, abs( clamp(position.z / glowRange, 0.0, 1.0) - time));\n" +
        //           "    gl_FragColor.rgb += gl_FragColor.rgb * (1.0 - diff);\n" +
        //           "}\n"
        //       })
        //       model._shouldRegenerateShaders = true
        //     }
        //   }
        // });
      });
    }).catch((e) => {
      console.log(e);
    });
  }

  /**
   * 3DTile 加载监听
   */
  tileLoadListener(tileListenerFn) {
    var helper = new Cesium.EventHelper();
    helper.add(this.viewer.scene.globe.tileLoadProgressEvent, function (event) {
      if (event == 0) {
        tileListenerFn && tileListenerFn();
      }
    });
  }

  /**
   * 改变tileset的高度
   * @param {Object} tileSet
   * @param {Number} height
   */
  changeHeight(tileSet, height) {
    height = Number(height);
    if (isNaN(height)) {
      return;
    }
    const cartographic = Cesium.Cartographic.fromCartesian(
      tileSet.boundingSphere.center
    );
    const surface = Cesium.Cartesian3.fromRadians(
      cartographic.longitude,
      cartographic.latitude,
      cartographic.height
    );
    const offset = Cesium.Cartesian3.fromRadians(
      cartographic.longitude,
      cartographic.latitude,
      height
    );
    const translation = Cesium.Cartesian3.subtract(
      offset,
      surface,
      new Cesium.Cartesian3()
    );
    tileSet.modelMatrix = Cesium.Matrix4.fromTranslation(translation);
  }

  /**
   * 修改tileset矩阵
   *
   * @param {*} tileset 3dTile
   * @param {*} m matrix对象
   */
  modifyTileSet(tileset, m) {
    tileset.modelMatrix = m;
  }

  /**
   * 设置矩阵x,y,z。主要用于设置3d tile位置
   *
   * @param {*} x
   * @param {*} y
   * @param {*} z
   * @return {*}
   */
  modifyOffsetModelMatrix(x, y, z) {
    var m = Cesium.Matrix4.fromArray([
      1.0,
      0.0,
      0.0,
      0.0,
      0.0,
      1.0,
      0.0,
      0.0,
      0.0,
      0.0,
      1.0,
      0.0,
      x,
      y,
      z,
      1.0,
    ]);
    return m;
  }

  /**
   * 编辑3dtile模型（旋转，平移等）
   *
   * @param {*} tileset 加载的3dtile
   * @param {*} option 选项
   * var defaultOption = {
      tx: cartographic.longitude, //模型中心X轴坐标（经度，单位：十进制度）
      ty: cartographic.latitude, //模型中心Y轴坐标（纬度，单位：十进制度）
      tz: 0.0, //模型中心Z轴坐标（高程，单位：米）
      rx: 0, //X轴（经度）方向旋转角度（单位：度）
      ry: 0, //Y轴（纬度）方向旋转角度（单位：度）
      rz: 0, //Z轴（高程）方向旋转角度（单位：度）
      scale: 1, //缩放比例
      };
   */
  update3dtilesMaxtrix(tileset, option) {
    var boundingSphere = tileset.boundingSphere;
    var cartographic = Cesium.Cartographic.fromCartesian(boundingSphere.center);
    //默认是模型经纬度。可根据自己传入的经度，纬度，高度决定tileset模型的位置
    var defaultOption = {
      tx: cartographic.longitude, //模型中心X轴坐标（经度，单位：十进制度）
      ty: cartographic.latitude, //模型中心Y轴坐标（纬度，单位：十进制度）
      tz: 0.0, //模型中心Z轴坐标（高程，单位：米）
      rx: 0, //X轴（经度）方向旋转角度（单位：度）
      ry: 0, //Y轴（纬度）方向旋转角度（单位：度）
      rz: 0, //Z轴（高程）方向旋转角度（单位：度）
      scale: 1, //缩放比例
    };

    var option = $.extend({}, defaultOption, option);

    var mx = Cesium.Matrix3.fromRotationX(Cesium.Math.toRadians(option.rx));

    var my = Cesium.Matrix3.fromRotationY(Cesium.Math.toRadians(option.ry));

    var mz = Cesium.Matrix3.fromRotationZ(Cesium.Math.toRadians(option.rz));

    var rotationX = Cesium.Matrix4.fromRotationTranslation(mx);

    var rotationY = Cesium.Matrix4.fromRotationTranslation(my);

    var rotationZ = Cesium.Matrix4.fromRotationTranslation(mz);

    var position = Cesium.Cartesian3.fromRadians(
      option.tx,
      option.ty,
      option.tz
    );
    //由模型原始经纬度转换
    var m = Cesium.Transforms.eastNorthUpToFixedFrame(position);

    //旋转、平移矩阵相乘

    Cesium.Matrix4.multiply(m, rotationX, m);

    Cesium.Matrix4.multiply(m, rotationY, m);

    Cesium.Matrix4.multiply(m, rotationZ, m);

    //赋值给tileset

    tileset._root.transform = m;

    //缩放

    this.zoom3dtiles(tileset, option);
  }

  /**
   * 缩放至3dTiles
   *
   * @param {*} tileset 3dTiles
   * @param {*} option 主要是选项的scale
   */
  zoom3dtiles(tileset, option) {
    var scale = (option.scale || 1) * 1;

    tileset._root.customTransform = {
      matrix: {
        origin: tileset._root.transform.clone(),

        rotation: Cesium.Matrix4.IDENTITY,

        translation: Cesium.Matrix4.IDENTITY,
      },
    };

    var m1 = Cesium.Matrix4.fromScale(
      new Cesium.Cartesian3(scale, scale, scale)
    );

    tileset._root.customTransform.matrix.scale = m1;

    tileset._root.customTransform.scale = scale;

    var m2 = new Cesium.Matrix4();

    Cesium.Matrix4.multiply(
      tileset._root.customTransform.matrix.origin,
      tileset._root.customTransform.matrix.rotation,
      m2
    );

    Cesium.Matrix4.multiply(m2, tileset._root.customTransform.matrix.scale, m2);

    Cesium.Matrix4.multiply(
      m2,
      tileset._root.customTransform.matrix.translation,
      tileset._root.transform
    );
  }
}
